﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DataScripter.Excel.Formatters;
using DataScripter.Excel.Formulas;

namespace DataScripter.Excel.Table
{
	class TableContent
	{
		public int NumberOfEmptyColumns { get; set; }
		public TableColumn[] Columns { get; private set; }
		public IList<TableRow> Rows { get; private set; }

		public ICell StartCell { get; set; }

		public TableContent(IEnumerable<string> columnNames)
		{
			Columns = columnNames.Select(c => new TableColumn(this, c)).ToArray();
			NumberOfEmptyColumns = Columns.TakeWhile(c => c.ColumnName == string.Empty).Count();
			for (int i = 0; i < Columns.Length; i++)
			{
				Columns[i].Index = i;
			}
			Rows = new List<TableRow>();
		}

		public TableContent(params string[] columnNames)
			: this((IEnumerable<string>)columnNames)
		{
		}

		public TableRow Add()
		{
			TableRow row = new TableRow(Rows.Count, Columns);
			Rows.Add(row);
			return row;
		}

		public TableRow Add(ICellFormatter formatter)
		{
			TableRow row = new TableRow(Rows.Count, formatter, Columns);
			Rows.Add(row);
			return row;
		}

		public TableRow AddDynamic(object o)
		{
			Type type = o.GetType();
			TableRow row = new TableRow(Rows.Count, Columns);
			foreach (TableColumn column in Columns)
			{
				PropertyInfo propertyInfo = type.GetProperty(column.ColumnName);
				if (propertyInfo != null)
				{
					object value = propertyInfo.GetValue(o, null);
					row.Set(column.ColumnName, value);
				}
			}
			Rows.Add(row);
			return row;
		}

		public TableRow Add(params object[] cells)
		{
			TableRow row = new TableRow(Rows.Count, Columns);
			row.Set(cells);
			Rows.Add(row);
			return row;
		}

		public TableColumn this[string columnName]
		{
			get { return Columns.Single(c => c.ColumnName == columnName); }
		}

		public Formulas.Table Table
		{
			get
			{
				int columns = Columns.SkipWhile(c => c.ColumnName == string.Empty).Count();
				return new Formulas.Table(StartCell, Rows.Count, columns);
			}
		}

		public Formula Lookup2Ref(string lookupValue, string columnName)
		{
			return this[columnName].Lookup2Ref(lookupValue);
		}
		public Formula Lookup2Ref(int lookupValue, string columnName)
		{
			return this[columnName].Lookup2Ref(lookupValue);
		}

		public Formula Lookup(Formula toLookup, string columnName)
		{
			return this[columnName].Lookup(toLookup);
		}
		public Formula Lookup(ICell toLookup, string columnName)
		{
			return this[columnName].Lookup(toLookup);
		}

		public Formula Ref(string columnName)
		{
			return this[columnName].Ref();
		}
		public Formula Ref(string columnName, int rowDiff)
		{
			return this[columnName].Ref(rowDiff);
		}
		public Formula RefAbsoluteRow(string columnName, int rowNr)
		{
			return this[columnName].RefAbsoluteRow(rowNr);
		}
		public Formula Last(string columnName)
		{
			return this[columnName].Last();
		}

		public Reference LookupReference(int value, TableColumn column)
		{
			string firstColumnName = Columns[NumberOfEmptyColumns].ColumnName;
			int rowNumber = Rows.Last(r => (int)(r[firstColumnName] ?? 0) <= value).RowNumber;
			return GetReference(rowNumber, column);
		}

		public Reference LookupReference(string value, TableColumn column)
		{
			string firstColumnName = Columns[NumberOfEmptyColumns].ColumnName;
			int rowNumber = Rows.First(r => (string)r[firstColumnName] == value).RowNumber;
			return GetReference(rowNumber, column);
		}

		private Reference GetReference(int rowNumber, TableColumn column)
		{
			ICell targetCell = StartCell.GetDiff(rowNumber, column.Index - NumberOfEmptyColumns);
			return new Reference(targetCell);
		}
	}
}